/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.auth.check.strategy;

import com.je.auth.check.AuthCheckEngine;
import com.je.auth.check.annotation.*;
import com.je.auth.check.util.FoxUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;

public class AuthCheckStrategy {

    private AuthCheckEngine authCheckEngine;

    public AuthCheckEngine getAuthCheckEngine() {
        return authCheckEngine;
    }

    public void setAuthCheckEngine(AuthCheckEngine authCheckEngine) {
        this.authCheckEngine = authCheckEngine;
    }

    /**
     * 判断：集合中是否包含指定元素（模糊匹配）
     * <p> 参数 [集合, 元素]
     */
    public BiFunction<List<String>, String, Boolean> hasElement = (list, element) -> {
        // 空集合直接返回false
        if (list == null || list.size() == 0) {
            return false;
        }

        // 先尝试一下简单匹配，如果可以匹配成功则无需继续模糊匹配
        if (list.contains(element)) {
            return true;
        }

        // 开始模糊匹配
        for (String patt : list) {
            if (FoxUtil.vagueMatch(element, patt)) {
                return true;
            }
        }

        // 走出for循环说明没有一个元素可以匹配成功
        return false;
    };

    /**
     * 对一个 [Method] 对象进行注解校验 （注解鉴权内部实现）
     * <p> 参数 [Method句柄]
     */
    public Consumer<Method> checkMethodAnnotation = (method) -> {

        // 先校验 Method 所属 Class 上的注解
        validateAnnotation(method.getDeclaringClass());

        // 再校验 Method 上的注解
        validateAnnotation(method);
    };

    /**
     * 对一个 [元素] 对象进行注解校验 （注解鉴权内部实现）
     * <p> 参数 [element元素]
     */
    public Consumer<AnnotatedElement> checkElementAnnotation = (element) -> {
        // 为了兼容旧版本
        validateAnnotation(element);
    };

    /**
     * 从指定元素校验注解
     *
     * @param target see note
     */
    public void validateAnnotation(AnnotatedElement target) {
        // 校验 @CheckLogin 注解
        AuthCheckLogin checkLogin = (AuthCheckLogin) getAnnotation.apply(target, AuthCheckLogin.class);
        if (checkLogin != null) {
            authCheckEngine.getAuthCheckManager().checkByAnnotation(checkLogin);
        }

        // 校验 @CheckRole 注解
        AuthCheckRole checkRole = (AuthCheckRole) getAnnotation.apply(target, AuthCheckRole.class);
        if (checkRole != null) {
            authCheckEngine.getAuthCheckManager().checkByAnnotation(checkRole);
        }

        // 校验 @CheckPermission 注解
        AuthCheckPermission checkPermission = (AuthCheckPermission) getAnnotation.apply(target, AuthCheckPermission.class);
        if (checkPermission != null) {
            authCheckEngine.getAuthCheckManager().checkByAnnotation(checkPermission);
        }

        // 校验 @CheckPermission 注解
        AuthCheckOrg checkOrg = (AuthCheckOrg) getAnnotation.apply(target, AuthCheckOrg.class);
        if (checkOrg != null) {
            authCheckEngine.getAuthCheckManager().checkByAnnotation(checkOrg);
        }

        // 校验 @CheckPermission 注解
        AuthCheckDept checkDept = (AuthCheckDept) getAnnotation.apply(target, AuthCheckDept.class);
        if (checkDept != null) {
            authCheckEngine.getAuthCheckManager().checkByAnnotation(checkDept);
        }

        // 校验 @CheckPermissionTempalte 注解
        AuthCheckPermissionTemplate checkPermissionTemplate = (AuthCheckPermissionTemplate) getAnnotation.apply(target, AuthCheckPermissionTemplate.class);
        if (checkPermissionTemplate != null) {
            authCheckEngine.getAuthCheckManager().checkByAnnotation(checkPermissionTemplate);
        }

    }

    /**
     * 从元素上获取注解（注解鉴权内部实现）
     * <p> 参数 [element元素，要获取的注解类型]
     */
    public BiFunction<AnnotatedElement, Class<? extends Annotation>, Annotation> getAnnotation = (element, annotationClass) -> {
        // 默认使用jdk的注解处理器
        return element.getAnnotation(annotationClass);
    };

    /**
     * 对一个 [Method] 对象进行注解校验 （注解鉴权内部实现）
     * <p> 参数 [Method句柄]
     *
     * @param checkMethodAnnotation /
     * @return 对象自身
     */
    public AuthCheckStrategy setCheckMethodAnnotation(Consumer<Method> checkMethodAnnotation) {
        this.checkMethodAnnotation = checkMethodAnnotation;
        return this;
    }

    /**
     * 对一个 [元素] 对象进行注解校验 （注解鉴权内部实现）
     * <p> 参数 [element元素]
     *
     * @param checkElementAnnotation /
     * @return 对象自身
     */
    public AuthCheckStrategy setCheckElementAnnotation(Consumer<AnnotatedElement> checkElementAnnotation) {
        this.checkElementAnnotation = checkElementAnnotation;
        return this;
    }

    /**
     * 从元素上获取注解（注解鉴权内部实现）
     * <p> 参数 [element元素，要获取的注解类型]
     *
     * @param getAnnotation /
     * @return 对象自身
     */
    public AuthCheckStrategy setGetAnnotation(BiFunction<AnnotatedElement, Class<? extends Annotation>, Annotation> getAnnotation) {
        this.getAnnotation = getAnnotation;
        return this;
    }

}
